/*
 * Created by SharpDevelop.
 * User: rseward
 * Date: 7/8/2008
 * Time: 3:19 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;

using RD.Metadata.Database.Sql;

using AvvaMobileNHibernateHelperKit.Framework;

namespace AvvaMobileNHibernateHelperKit
{
	/// <summary>
	/// Description of VbNetClassGenerator.
	/// </summary>
	public class VbNetClassGenerator : BaseClassCodeGenerator
	{
		Dictionary<string, string> prefixMap = new Dictionary<string, string>();
		Dictionary<string, string> typeMap = new Dictionary<string, string>();
		
		public VbNetClassGenerator(MainForm form, Data dataClass, Project project) : base(form, dataClass, project)
		{
			//this.form = form;
			//this.dataClass = dataClass;
			//this.project = project;			
			
			prefixMap[ "private" ] = "Private";
			
			typeMap[ "int" ] = "Integer";
			typeMap[ "bool" ] = "Boolean";			
			typeMap[ "bool?" ] = "Nullable(Of Boolean)";
			typeMap[ "int?" ] = "Nullable(Of Integer)";
			typeMap[ "double" ] = "Double";
			typeMap[ "double?" ] = "Nullable(Of Double)";
			typeMap[ "float" ] = "Float";
			typeMap[ "float?" ] = "Nullable(Of Float)";

		}
		
		public string MapPrefix(string prefix)
		{
			string mapval = prefix;

			if (prefixMap.ContainsKey( prefix) ) {
				mapval = prefixMap[ prefix ];
			}
			
			return mapval;
		}
		
		public string MapType(string type)
		{
			string mapval = type;

			if (typeMap.ContainsKey( type) ) {
				mapval = typeMap[ type ];
			}
			
			return mapval;
			
		
		}
		
		public string GetFieldType(string fieldType)
		{
			Match mat = Regex.Match( fieldType, @"(.*?)\?");
			if (mat.Success) {
				fieldType = String.Format("Nullable(Of {0})", mat.Groups[1]);				
			}
			return fieldType;
		}
		
		public string FormatFieldDeclaration(Dictionary<string,string> fieldDecl)
		{
			string fieldPrefix = MapPrefix( fieldDecl[ "fieldPrefix" ] );
			string fieldName = "_"+fieldDecl[ "fieldName" ];
			string fieldType = MapType( fieldDecl[ "fieldType" ] );
			fieldType = GetFieldType( fieldType );
												
			string fieldDeclaration =  fieldPrefix + " " + fieldName + " As " + fieldType  ;
			
			return fieldDeclaration;
		}
		
		public string FormatPropertyDeclaration(Dictionary<string,string> fieldDecl)
		{
			StringBuilder buf = new StringBuilder( 200 );
			
			string colName = fieldDecl[ "propName" ];
			string fieldName = "_"+fieldDecl[ "fieldName" ];
			string fieldType = MapType( fieldDecl[ "fieldType" ] );
			fieldType = GetFieldType( fieldType );
			
			string crlf = Constants.CRLF ;
						
			buf.Append("Public Overridable Property " + colName + "() As " + fieldType + crlf);
            buf.Append("  Get" + crlf);
            buf.Append("    Return " + fieldName+ crlf);
            buf.Append("  End Get"+crlf+crlf);
            buf.Append("  Set(ByVal value As " + fieldType + ")"+crlf);
            buf.Append("     "+fieldName + " = value"+crlf);
            buf.Append("  End Set"+crlf);
            buf.Append("End Property"+crlf+crlf);
			
			return ""+buf;		
		}
				
		public override void GenerateClasses()
		{

                form.Progress("Persistent classes generating", 35);
                foreach (string tableName in project.SelectedTables)
                {                	
                	string className = project.NameFormatter.GetClassName(tableName);
                	
                	System.IO.StreamWriter classSw = new System.IO.StreamWriter(project.ProjectDir + @"\App_Code\" + className + ".vb");
                	classSw.WriteLine("' " + GeneratedByText );
                	classSw.WriteLine("");
                	classSw.WriteLine("Imports System");
                	classSw.WriteLine("");
                	classSw.WriteLine("Namespace " + project.Namespace);
                	classSw.WriteLine("");
                	classSw.WriteLine("Public Class " + className);
                	classSw.WriteLine("");
                	
                	form.Progress("Capturing table columns schema", 0);
                	
                	SqlMetaTable tabMeta = dataClass.GetTableInfo( tableName );
                	
                	if (tabMeta == null) {
                		throw new Exception("Unable to find meta data for "+tableName);
                	}

                	form.Progress("Writing fields and propertied for Class " + className , 0);
                	#region Writing Fields and Properties
                	List<string> fieldDecls = new List<string>();
                	List<string> propDecls = new List<string>();
                	
                	foreach (SqlMetaColumn col in tabMeta.Columns)
                	{
                		string colName = col.ColumnName;
                		string fieldName = project.NameFormatter.GetFieldName( className, col.ColumnName);
                		string propName = project.NameFormatter.GetPropertyName( className, col.ColumnName);
                		
                		string fieldDecl = FormatFieldDeclaration( project.DbDriver.GetClassFieldDeclaration(project, className, col, fieldName)  );
                		string propDecl = FormatPropertyDeclaration( project.DbDriver.GetClassPropertyDeclaration(project, className, col, fieldName, propName ) );
                		
                		fieldDecls.Add( fieldDecl );
                		propDecls.Add( propDecl );
                		
                		
                		
                		/*
                		switch (dr["col_typename"].ToString())
                		{
                				case "int": classSw.WriteLine("Protected " + " _" + colName + " As Integer"); break;
                				case "tinyint": classSw.WriteLine("Protected " + "_" + colName + " As Integer"); break;
                				case "smallint": classSw.WriteLine("Protected " + "_" + colName + " As Integer"); break;
                				case "bigint": classSw.WriteLine("Protected " + "_" + colName + " As Integer"); break;
                				case "char": classSw.WriteLine("Protected " + "_" + colName + " As String"); break;
                				case "varchar": classSw.WriteLine("Protected " + "_" + colName + " As String"); break;
                				case "nchar": classSw.WriteLine("Protected " + "_" + colName + " As String"); break;
                				case "nvarchar": classSw.WriteLine("Protected " + "_" + colName + " As String"); break;
                				case "datetime": classSw.WriteLine("Protected " + "_" + colName + " As Date"); break;
                				case "smalldatetime": classSw.WriteLine("Protected " + "_" + colName + " As Date"); break;
                				case "money": classSw.WriteLine("Protected " + "_" + colName + " As Decimal"); break;
                				case "decimal": classSw.WriteLine("Protected " + "_" + colName + " As Decimal"); break;
                				case "smallmoney": classSw.WriteLine("Protected " + "_" + colName + " As Decimal"); break;
                				case "bit": classSw.WriteLine("Protected " + "_" + colName + " As Boolean"); break;
                				case "uniqueidentifier": classSw.WriteLine("Protected " + "_" + colName + " As Guid"); break;
                				case "text": classSw.WriteLine("Protected " + "_" + colName + " As String"); break;
                				case "ntext": classSw.WriteLine("Protected " + "_" + colName + " As String"); break;
                		} */

                	}
                	
                	foreach (string fieldDecl in fieldDecls) {
                		classSw.WriteLine( fieldDecl);
                	}
                	
                	classSw.WriteLine("");
                	classSw.WriteLine("");
                	
                	foreach (string propDecl in propDecls) {
                		classSw.WriteLine( propDecl );
                	}
                	classSw.WriteLine("");
                	classSw.WriteLine("");                	
                	#endregion
                	form.Progress("Fields and properties applied for Class " + className, 0);

                	classSw.WriteLine("End Class");
                	classSw.WriteLine("End Namespace");
                	classSw.Flush();
                	classSw.Close();
                	classSw.Dispose();
                	form.Progress("Class file " + className + " generated" , 0);
                }
                

                form.Progress("Persistent classes generated", 60);

		}
	}
}
